package com.yunhe.option.service.data.impl;

import com.yunhe.option.domain.data.SeasonPrice;
import com.yunhe.option.domain.data.SeasonPriceDetail;
import com.yunhe.common.exception.ArgumentErrorException;
import com.yunhe.common.exception.ObjectNotFoundException;
import com.yunhe.common.exception.UniqueConstraintsException;
import com.yunhe.option.repository.data.SeasonPriceRepository;
import com.yunhe.option.service.data.SeasonPriceDetailService;
import com.yunhe.option.service.data.SeasonPriceService;
import com.yunhe.common.util.StringUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 季节电价服务类实现
 * @author liuronglei
 */
@Service
public class SeasonPriceServiceImpl implements SeasonPriceService {
    @Autowired
    private SeasonPriceRepository seasonPriceRepository;
    @Autowired
    private SeasonPriceDetailService seasonPriceDetailService;

    private void processBeforeSave(SeasonPrice seasonPrice, Long costPriceId)
        throws ArgumentErrorException, UniqueConstraintsException, ObjectNotFoundException{
        if (seasonPrice.getTitle() == null
                || seasonPrice.getRunMonth() == null
                || seasonPrice.getPriceRates() == null
                || seasonPrice.getSeasonPriceDetails() == null) {
            throw new ArgumentErrorException("参数不能为空");
        }
        String seasonPriceTitle = seasonPrice.getTitle();
        if (StringUtil.isEmpty(seasonPriceTitle)) {
            throw new ArgumentErrorException("季节标题不能为空");
        }
        String runMonth = seasonPrice.getRunMonth();
        if (StringUtil.isEmpty(runMonth)) {
            throw new ArgumentErrorException("适用月份不能为空");
        }
        List<Long> priceRates = seasonPrice.getPriceRates();
        if (priceRates.isEmpty()) {
            throw new ArgumentErrorException("电价费率不能为空");
        }
        List<SeasonPriceDetail> detailList = seasonPrice.getSeasonPriceDetails();
        if (detailList == null) {
            throw new ArgumentErrorException("时段不能为空");
        }
        SeasonPrice seasonPriceByTitle = seasonPriceRepository.findByCostPriceIdAndTitle(costPriceId, seasonPrice.getTitle());
        if (seasonPriceByTitle != null) {
            if (seasonPrice.getId() == null || seasonPriceByTitle.getId().longValue() != seasonPrice.getId().longValue()) {
                throw new UniqueConstraintsException("已存在名称为" + seasonPriceTitle + "的季节电价");
            }
        }
        //判断季节电价详情所有时段是否存在交集
        List<SeasonPriceDetail> seasonPriceDetails = seasonPrice.getSeasonPriceDetails();
        if (seasonPriceDetails != null && seasonPriceDetails.size() > 0) {
            List<Map<String, Date>> list = new ArrayList<>();
            //判断同一季节电价下的所有时段是否存在交集
            for(SeasonPriceDetail detail : seasonPriceDetails) {
                Map<String, Date> map = new HashMap<>();
                map.put("startTime", detail.getStartTime());
                map.put("endTime", detail.getEndTime());
                list.add(map);
            }
            //排序
            sortMap(list, "startTime");
            SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
            Calendar calendar = Calendar.getInstance();
            for(int i = 0; i < list.size() - 1; i++) {
                Map<String, Date> map = list.get(i);
                Map<String, Date> nextMap = list.get(i+1);
                Date endTime = map.get("endTime");
                calendar.setTime(endTime);
                int endHour = calendar.get(Calendar.HOUR_OF_DAY);
                int endMinute = calendar.get(Calendar.MINUTE);
                int endSecond = calendar.get(Calendar.SECOND);
                Date nextStartTime = nextMap.get("startTime");
                calendar.setTime(nextStartTime);
                int nextStartHour = calendar.get(Calendar.HOUR_OF_DAY);
                int nextStartMinute = calendar.get(Calendar.MINUTE);
                int nextStartSecond = calendar.get(Calendar.SECOND);
                if ("00:00:00".equals(sdf.format(nextStartTime))) {
                    throw new ArgumentErrorException("同一季节电价下所有时段不可存在交集，请重新填写");
                } else if (endHour > nextStartHour) {
                    throw new ArgumentErrorException("同一季节电价下所有时段不可存在交集，请重新填写");
                } else if (endHour == nextStartHour && endMinute > nextStartMinute) {
                    throw new ArgumentErrorException("同一季节电价下所有时段不可存在交集，请重新填写");
                } else if (endHour == nextStartHour && endMinute == nextStartMinute && endSecond > nextStartSecond) {
                    throw new ArgumentErrorException("同一季节电价下所有时段不可存在交集，请重新填写");
                }
                //判断单个季节电价下的所有时段是否包含0:00~24:00范围所有时间
                Map<String, Date> startMap = list.get(0);
                Map<String, Date> endMap = list.get(list.size() - 1);
                if (!"00:00:00".equals(sdf.format(startMap.get("startTime"))) || !"00:00:00".equals(sdf.format(endMap.get("endTime")))) {
                    throw new ArgumentErrorException("季节电价下的所有时段必须完整24小时");
                }
            }
        }
    }

    /**
     * 给List<Map>排序
     * @param list
     * @param sortField
     */
    private void sortMap(List<Map<String, Date>> list, String sortField) {
        list.sort((o1, o2) -> {
            Date date1 = o1.get(sortField);
            Date date2 = o2.get(sortField);
            return date1.compareTo(date2);
        });
    }

    /**
     * 新增季节电价对象
     * @param seasonPrice
     * @param costPriceId
     * @return
     * @throws ArgumentErrorException
     * @throws UniqueConstraintsException
     * @throws ObjectNotFoundException
     */
    @Transactional(rollbackFor = Exception.class, transactionManager = "transactionManager")
    @Override
    public SeasonPrice create(SeasonPrice seasonPrice, Long costPriceId)
            throws ArgumentErrorException, UniqueConstraintsException, ObjectNotFoundException {
        processBeforeSave(seasonPrice, costPriceId);
        List<SeasonPriceDetail> details = seasonPrice.getSeasonPriceDetails();
        seasonPrice.setId(null);
        SeasonPrice newSeason =  seasonPriceRepository.save(seasonPrice);
        seasonPriceRepository.bindCostPrice(newSeason.getId(), costPriceId);
        List<Long> priceRates = newSeason.getPriceRates();
        seasonPriceRepository.bindPriceRate(newSeason.getId(), priceRates);
        newSeason.setSeasonPriceDetails(details);
        if (details != null) {
            seasonPriceDetailService.create(details, newSeason.getId());
        }
        return newSeason;
    }

    /**
     * 批量新增季节电价对象
     * @param list
     * @param costPriceCode
     * @return
     * @throws ArgumentErrorException
     * @throws UniqueConstraintsException
     * @throws ObjectNotFoundException
     */
    @Transactional(rollbackFor = Exception.class, transactionManager = "transactionManager")
    @Override
    public Iterable<SeasonPrice> create(List<SeasonPrice> list, Long costPriceCode)
            throws ArgumentErrorException, UniqueConstraintsException, ObjectNotFoundException {
        Iterable<SeasonPrice> newSeasonPrices = seasonPriceRepository.saveAll(list);
        for(SeasonPrice seasonPrice : newSeasonPrices) {
            this.create(seasonPrice, costPriceCode);
        }
        return newSeasonPrices;
    }

    /**
     * 根据ID删除季节电价和所属的季节电价详情
     * @param seasonPriceId
     * @throws ArgumentErrorException
     */
    @Transactional(rollbackFor = Exception.class, transactionManager = "transactionManager")
    @Override
    public void delete(Long seasonPriceId) throws ArgumentErrorException {
        SeasonPrice seasonPrice = this.findById(seasonPriceId).get();
        if (seasonPrice != null) {
            try{
                seasonPriceRepository.deleteSeasonPrice(seasonPriceId);
            } catch (Exception e) {
                throw new ArgumentErrorException("删除失败");
            }
        }
    }

    /**
     * 批量删除季节电价和所属的季节电价详情
     * @param list
     * @throws ArgumentErrorException
     */
    @Transactional(rollbackFor = Exception.class, transactionManager = "transactionManager")
    @Override
    public void delete(List<SeasonPrice> list) throws ArgumentErrorException {
        for(SeasonPrice price : list) {
            SeasonPrice seasonPrice = this.findById(price.getId()).get();
            if (seasonPrice != null) {
                try{
                    seasonPriceRepository.deleteSeasonPrice(seasonPrice.getId());
                } catch (Exception e) {
                    throw new ArgumentErrorException("删除失败");
                }
            }
        }
    }

    /**
     * 更新季节电价（全部字段）
     * @param seasonPrice
     * @return
     * @throws ArgumentErrorException
     * @throws UniqueConstraintsException
     * @throws ObjectNotFoundException
     */
    @Transactional(rollbackFor = Exception.class, transactionManager = "transactionManager")
    @Override
    public SeasonPrice update(SeasonPrice seasonPrice)
            throws ArgumentErrorException, UniqueConstraintsException, ObjectNotFoundException {
        boolean exists = seasonPrice.getId() != null && seasonPriceRepository.existsById(seasonPrice.getId());
        if (!exists) {
            throw new ObjectNotFoundException("找不到ID为" + seasonPrice.getId() + "的季节电价");
        }
        Long costPriceId = seasonPriceRepository.findCostPriceId(seasonPrice.getId());
        processBeforeSave(seasonPrice, costPriceId);
        return seasonPriceRepository.save(seasonPrice);
    }

    /**
     * 更新季节电价（指定字段）
     * @param id
     * @param title
     * @param runMonth
     * @param priceRates
     * @param details
     * @return
     * @throws ArgumentErrorException
     * @throws UniqueConstraintsException
     * @throws ObjectNotFoundException
     */
    @Transactional(rollbackFor = Exception.class, transactionManager = "transactionManager")
    @Override
    public SeasonPrice update(Long id,
                              String title,
                              String runMonth,
                              List<Long> priceRates,
                              List<SeasonPriceDetail> details)
            throws ArgumentErrorException, UniqueConstraintsException, ObjectNotFoundException {
        SeasonPrice seasonPrice = this.findById(id).get();
        if (seasonPrice == null) {
            throw new ObjectNotFoundException("找不到ID为" + seasonPrice.getId() + "的季节电价");
        }
        Optional.ofNullable(title).ifPresent(seasonPrice::setTitle);
        Optional.ofNullable(runMonth).ifPresent(seasonPrice::setRunMonth);
        Optional.ofNullable(priceRates).ifPresent(seasonPrice::setPriceRates);
        Optional.ofNullable(details).ifPresent(seasonPrice::setSeasonPriceDetails);
        return seasonPriceRepository.save(seasonPrice);
    }

    /**
     * 根据ID查找季节电价
     * @param id
     * @return
     */
    @Override
    public Optional<SeasonPrice> findById(Long id) {
        return seasonPriceRepository.findById(id);
    }

    /**
     * 根据条件查找季节电价
     * @param costPriceId
     * @return
     */
    @Override
    public List<SeasonPrice> search(Long costPriceId) {
        if (costPriceId != null) {
            return seasonPriceRepository.findSeasonPriceByCostPrice(costPriceId);
        }
        return null;
    }
}
